package middleware

import (
	"fmt"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/connector/orm"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/gin/log"
	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/toolfunc"
	"github.com/casbin/casbin"
	"github.com/gin-gonic/gin"

	"gitee.com/wuzheng0709/backend-gopkg/infrastructure/pkg/code"
)

type AdminUserRole struct {
	ID     int64 `gorm:"column:id;primary_key;AUTO_INCREMENT" form:"id"   json:"id"`
	UserID int64 `gorm:"column:user_id;not null;"` // 管理员ID
	RoleID int64 `gorm:"column:role_id;not null;"` // 角色ID
}

const (
	PrefixUserID = "u_"
	PrefixRoleID = "r_"
)

var enforcer *casbin.Enforcer

// 检查用户是否有权限
func CasbinCheckPermission(userID, url, methodtype string) (bool, error) {
	log.Infof("检查权限:%v  %v  %v %v ", PrefixUserID+userID, url, methodtype, enforcer)
	flag, err := enforcer.EnforceSafe(PrefixUserID+userID, url, methodtype)
	if flag {
		return flag, err
	}
	var adminsroles []AdminUserRole
	orm.Find(orm.GetMysqlDB(), &AdminUserRole{UserID: toolfunc.String2Int64(userID)}, &adminsroles)
	for _, adminsrole := range adminsroles {
		flag, err = enforcer.EnforceSafe(PrefixRoleID+toolfunc.Int642String(adminsrole.RoleID), url, methodtype)
		if flag {
			return flag, err
		}
	}
	return flag, err
}

// CasbinMiddleware casbin中间件
func CasbinMiddleware(skipper ...SkipperFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(skipper) > 0 && skipper[0](c) {
			c.Next()
			return
		}
		var sub string
		var obj, act string
		obj = c.Request.URL.Path
		method := c.Request.Method
		switch method {
		case "GET":
			act = "read"
		case "POST":
			act = "write"
		default:
			c.Next()
			return
		}
		sub = c.GetString("UID")
		log.Infof("权限认证:%v  %v  %v", sub, obj, act)
		if b, err := CasbinCheckPermission(sub, obj, act); err != nil {
			c.JSON(500, gin.H{
				"code": code.Crash_Error,
				"msg":  fmt.Sprintf("验证服务出现错误:%v", err),
			})
			c.Abort()
		} else if !b {
			c.JSON(400, gin.H{
				"code": code.Token_Error,
				"msg":  "没有权限",
			})
			c.Abort()
		}
		c.Next()
	}
}
